﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace PssFramework
{

    namespace PSServer
    {

        class PublisherService
        {
            static EventHandler OnServerEvent;
            public void StartPublisherService(EventHandler OnServerEvent)
            {
                OnServerEvent.Invoke(null, new ServerEventArgs("Starting Publish service"));
                PublisherService.OnServerEvent = OnServerEvent;
                  Thread th = new Thread(new ThreadStart(HostPublisherService));
                th.IsBackground = true;
                th.Start();
            }

            private void HostPublisherService()
            {
                try
                {
                    IPAddress ipV4 = IPAddress.Parse(Config.getInstance().HostIp);
                    IPEndPoint localEP = new IPEndPoint(ipV4, Config.getInstance().PublishPort);
                    Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
                    server.Bind(localEP);

                    StartListening(server);
                }
                catch (Exception exc)
                {
                    string str = exc.ToString();

                }
            }
        
            private static void StartListening(Socket server)
            {
                OnServerEvent.Invoke(null, new ServerEventArgs("Pub serv start listening"));

                EndPoint remoteEP = new IPEndPoint(IPAddress.Any, 0);
                int recv = 0;
                byte[] data =null;
                while (true)
                {
                    try
                    {
                        recv = 0;
                        data = new byte[1024];
                        recv = server.ReceiveFrom(data, ref remoteEP);
                        PssFramework.EPPSCommands Cmd = (PssFramework.EPPSCommands)Utils.getValue(data, 0);
                        int Topic = Utils.getValue(data, 4);
                        byte[] TopicData = new byte[recv - 8];
                        Array.Copy(data, 8, TopicData, 0, TopicData.Length);
                        switch (Cmd)
                        {
                            case PssFramework.EPPSCommands.PUBLISH:
                                {
                                    OnServerEvent.Invoke(null, new ServerEventArgs("PublishCommand"));
                                    List<EndPoint> subscriberListForThisTopic = Filter.GetSubscribers(Topic);
                                    WorkerThreadParameters workerThreadParameters = new WorkerThreadParameters();
                                    workerThreadParameters.Server = server;
                                    workerThreadParameters.Message = TopicData;
                                    workerThreadParameters.SubscriberListForThisTopic = subscriberListForThisTopic;

                                    ThreadPool.QueueUserWorkItem(new WaitCallback(Publish), workerThreadParameters);

                                }
                                break;
                        }

                    }
                    catch
                    { }

                }
            }

            public static void Publish(object stateInfo)
            {
                WorkerThreadParameters workerThreadParameters = (WorkerThreadParameters)stateInfo;
                Socket server = workerThreadParameters.Server;
                byte[] message = workerThreadParameters.Message;
                List<EndPoint> subscriberListForThisTopic = workerThreadParameters.SubscriberListForThisTopic;
                int messagelength = message.Length;

                if (subscriberListForThisTopic != null)
                {
                    foreach (EndPoint endPoint in subscriberListForThisTopic)
                    {
                        server.SendTo(message, messagelength, SocketFlags.None, endPoint);

                    }
                }
            }

            private static string MakeCommaSeparatedString(List<string> eventParts)
            {
                string message = string.Empty;
                foreach (string item in eventParts)
                {
                    message = message + item + ",";

                }
                if (message.Length != 0)
                {
                    message = message.Remove(message.Length - 1, 1);
                }
                return message;
            }
        }
        class WorkerThreadParameters
        {
            Socket _server;

            public Socket Server
            {
                get { return _server; }
                set { _server = value; }
            }
            byte[] _message;

            public byte[] Message
            {
                get { return _message; }
                set { _message = value; }
            }
            List<EndPoint> _subscriberListForThisTopic;

            public List<EndPoint> SubscriberListForThisTopic
            {
                get { return _subscriberListForThisTopic; }
                set { _subscriberListForThisTopic = value; }
            }

        }
    }
}